﻿using CityGrid.Common.Utilities;
using CQRSFramework.Common.Components;
using CQRSFramework.Domains;
using CQRSFramework.Events;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;

namespace CQRSFramework.Commands.Impl
{
    public class DefaultCommandProcess : ICommandProcess
    {
        private readonly IProcessingCommandHandler _handler;
        private ConcurrentDictionary<Type, CommandExecutionInfo> _dic = new ConcurrentDictionary<Type, CommandExecutionInfo>();
        private ConcurrentDictionary<string, CommandMailBox> _actorDict = new ConcurrentDictionary<string, CommandMailBox>();

        public DefaultCommandProcess(IProcessingCommandHandler handler)
        {
            _handler = handler;
        }

        public void Process(ICommand command, ICommandContext context, IModel _channel, BasicDeliverEventArgs _ea)
        {
            var mailBox = _actorDict.GetOrAdd(command.AggregateRootId, x =>
             {
                 return new CommandMailBox(command.AggregateRootId, _handler);
             });
            mailBox.Enqueue(new ProcessingCommand() { Channel = _channel, Command = command, CommandContext = context, EA = _ea });
        }
        class CommandExecutionInfo
        {
            public Type CommandHandlerType { get; set; }
            public Action<object, ICommandContext, ICommand> Invoke { get; set; }
        }
        private CommandExecutionInfo GetCommandExecutionInfo(Type type)
        {
            CommandExecutionInfo subscriberInfo;
            if (!_dic.TryGetValue(type, out subscriberInfo))
            {
                var handlerType = typeof(ICommandHandler<>).MakeGenericType(type);
                subscriberInfo = new CommandExecutionInfo
                {
                    CommandHandlerType = handlerType,
                    Invoke = DelegateFactory.CompileMethodInvocation<Action<object, ICommandContext, ICommand>>(handlerType, "Handle")
                };
                _dic.TryAdd(type, subscriberInfo);
            }
            return subscriberInfo;
        }
    }
}
